#   Trolls Outta Luckland v0.0.7
#   Copyright 2009-2010, Gummbum
#
#   This file is part of Trolls Outta Luckland.
#
#   Trolls Outta Luckland is free software: you can redistribute it
#   and/or modify it under the terms of the GNU General Public License
#   as published by the Free Software Foundation, either version 3 of
#   the License, or (at your option) any later version.
#
#   Trolls Outta Luckland is distributed in the hope that it will be
#   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
#   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with Trolls Outta Luckland.  If not, see
#   <http://www.gnu.org/licenses/>.

__version__ = '0.0.7'

### Python imports
import os
from os.path import join as join_path
import sys

try:
    ### Pygame imports
    import pygame
    from pygame.locals import Color, RLEACCEL
    ### Game library imports
    import game_globals
    from game_globals import *
    import powerups
    import settings
    from utils import (
        constrain, draw_text, get_font, make_font, game_to_mouse,
        mouse_to_game, load_image, split_thousands,
    )
except ImportError, e:
    print 'ImportError: %s' % e
    print '    in file "%s"' % os.path.abspath(sys.argv[0])

def layout():
    global _layout
    if _layout is None:
        _layout = _UILayout()
    return _layout
_layout = None

def color(name):
    return colors[name]
colors = {
    'transparent' : Color(1,1,1),
    'system' : Color('yellow'),
    'stats' : Color('white'),
    'score text' : Color('yellow1'),
}

class Fader(object):
    def __init__(self, max, secs):
        """Alpha fader: try max=255, secs=2"""
        max_fps = game_globals.game.max_fps
        self.max = max
        self.val = max
        self.step = self.i = 4/secs * 120.0/max_fps/600
    def __iter__(self):
        self.val = self.max
        self.i = self.step
        return self
    def next(self):
        if self.val <= 0:
            raise StopIteration
        self.val += (-9.8 * self.i**2)
        self.i += self.step
        return self.val

class _UILayout(object):
    def __init__(self):
        game = game_globals.game
        height = game.window.rect.height
        game_rect = game.window.rect
        font_height,font_width = get_font('gui small').size('W')
        self.fps = (12,10)
        # anchored topleft
        self.player_name = (12, 10+font_height*2)
        self.stage = (game_rect.width*1/4, 10+font_height*2)
        # anchored topcenter
        self.score = (game_rect.centerx, 10+font_height*2)
        self.now_playing = (game_rect.centerx, 10)
        # anchored bottomleft
        self.ships = (12, game_rect.bottom-8)

class UILabel(pygame.sprite.Sprite):
    def __init__(self, text, pos, font_name='gui small'):
        pygame.sprite.Sprite.__init__(self)
        self.text = text
        self.image = get_font(font_name).render(text, True, color('system'))
        self.rect = self.image.get_rect()
        self.rect.topright = pos

class Herald(pygame.sprite.Sprite):
    def __init__(self, text, line=0, pulse=False, font_name='gui'):
        pygame.sprite.Sprite.__init__(self)
        self.surface = game_globals.game.window.surface
        self.text = text
        self.line = line
        self.font = get_font(font_name)
        self.fg = color('system')
        self.bg = color('transparent')
        self.alpha = 255
        self.alpha_tick = 2 * game_globals.game.speed()
        self.pulse = pulse
        self.rect = None
        self.render_text()
        self.center()
        self.set_line(line)
    def update(self, *args):
        if self.pulse:
            tick = self.alpha_tick
            alpha = self.alpha + tick
            if alpha > 255:
                alpha = 255
                tick = -(tick)
            elif alpha < 130:
                alpha = 130
                tick = -(tick)
            self.alpha = alpha
            self.alpha_tick = tick
        self.image.set_alpha(self.alpha)
    def set_color(self, color):
        self.fg = color
        self.render_text()
    def set_text(self, text):
        self.text = text
        self.render_text()
    def render_text(self):
        if self.rect is not None:
            save_pos = self.rect.center
        else:
            save_pos = 0,0
        self.image = self.font.render(self.text, True, self.fg, self.bg)
        self.image.set_colorkey(self.bg, RLEACCEL)
        self.rect = self.image.get_rect()
        self.rect.center = save_pos
    def set_line(self, line):
        self.line = line
        surf_rect = self.surface.get_rect()
        font_width,font_height = self.font.size('W')
        self.rect.centery = int(surf_rect.height*5/12) + (font_height+4)*self.line
    def center(self):
        self.rect.centerx = self.surface.get_rect().centerx
    def set_pulse(self, pulse=True):
        self.pulse = pulse
        if pulse is False:
            self.alpha = 255

class NowPlaying(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.font = get_font('gui small')
        self.set_text('none')
    def set_text(self, text):
        self.image = self.font.render(
            'Now playing [%s]'%text, True, color('system'), color('transparent'))
        self.image.set_colorkey(color('transparent'), RLEACCEL)
        self.image.set_alpha(208)
        self.rect = self.image.get_rect()
        self.rect.centerx,self.rect.top = layout().now_playing

class Stat(pygame.sprite.Sprite):
    def __init__(self, text, pos):
        pygame.sprite.Sprite.__init__(self)
        self.font = get_font('gui small')
        self.text = text
        self.image = self.font.render(
            text, True, color('system'), color('transparent'))
        self.image.set_colorkey(color('transparent'), RLEACCEL)
        self.image.set_alpha(208)
        self.rect = self.image.get_rect()
        self.rect.topleft = pos

class Statf(pygame.sprite.Sprite):
    def __init__(self, text, pos, value):
        pygame.sprite.Sprite.__init__(self)
        self.font = get_font('gui small')
        self.text = text
        self.value = None
        self.set_value(value)
        self.rect = self.image.get_rect()
        self.rect.topleft = pos
    def set_value(self, value):
        if value is not None and value != self.value:
            self.value = value
            self.image = self.font.render(
                self.text%value, True, color('system'), color('transparent'))
            self.image.set_colorkey(color('transparent'), RLEACCEL)
        self.image.set_alpha(208)

class ShipCounter(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        image = game_globals.game.player.anim.images[0][0].copy()
        self.small_rect = image.get_rect()
        sr = self.small_rect
        w,h = int(sr.width/2), int(sr.height/2)
        try:
            self.small_image = pygame.transform.smoothscale(image, (w,h))
        except:
            self.small_image = pygame.transform.scale(image, (w,h))
        self.small_image.set_colorkey(self.small_image.get_at((0,0)), RLEACCEL)
        self.small_rect = sr = self.small_image.get_rect()
        w,h = (sr.width+2)*MAX_LIVES, sr.height
        self.rect = pygame.Rect(0,0,w,h)
        self.rect.bottomleft = layout().ships
        self.image = pygame.surface.Surface(self.rect.size)
        self.image.fill(color('transparent'))
        self.image.set_colorkey(color('transparent'), RLEACCEL)
        self.image.convert()
        # plus 1 for show; we lose one when game starts
        self.lives = INITIAL_LIVES+1
        self.prev_lives = -1
    def max_size(self):
        height = self.small_rect.height
        width = MAX_LIVES * (self.small_rect.width+2)
        return width,height
    def lose(self):
        if self.lives > 0:
            self.lives -= 1
            self.update()
    def gain(self):
        if self.lives < MAX_LIVES:
            game = game_globals.game
            self.lives += 1
            self.update()
            r = self.small_rect.copy()
            r.topleft = self.rect.topleft
            r.x += (r.w+2) * (self.lives-2)
            game.stats.add(powerups.DebrisNova(r.center, game.max_fps))
    def update(self, *args):
        if self.lives != self.prev_lives:
            self.prev_lives = self.lives
            sr = self.small_rect.copy()
            r = self.rect
            self.image.fill(color('transparent'))
            if self.lives > 0:
                for i in range(1, self.lives):
                    self.image.blit(self.small_image, sr)
                    sr.left += sr.width + 2
            sys.stdout.flush()
    def reset(self):
        # plus 1 for show; we lose one when game starts
        self.lives = INITIAL_LIVES+1
        self.prev_lives = -1
        self.update()

class Score(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.value = 0
        self.prev_value = -1
        self.image = None
        self.update()
    def update(self, *args):
        if self.value != self.prev_value:
            text = '%003d' % self.value
            text = split_thousands(text)
            self.image = get_font('gui').render(
                text, True, color('stats'), color('transparent'))
            self.image.set_colorkey(color('transparent'), RLEACCEL)
            self.rect = self.image.get_rect()
            self.rect.centerx,self.rect.top = layout().score
            self.prev_value = self.value
    def add(self, value, bonus, pos):
        self.value += value * bonus
        ScoreText(value, bonus, pos)
    def reset(self):
        self.value = 0
        self.prev_value = -1
        self.update()

class ScoreText(pygame.sprite.Sprite):
    def __init__(self, value, bonus, pos):
        pygame.sprite.Sprite.__init__(self)
        game = game_globals.game
        self.value = value
        self.bonus = bonus
        self.pos = pos
#        self.alpha = 255
        score_text = '%d'%round(value)
        fg = color('score text')
        bg = color('transparent')
        if bonus > 1:
            score_text += ' '
            bonus_text = 'x%d'%round(bonus)
            fn_score = 'score text'
            fn_bonus = 'score text %d'%round(bonus)
            score_width,score_height = get_font(fn_score).size(score_text)
            bonus_width,bonus_height = get_font(fn_bonus).size(bonus_text)
            width,height = score_width+bonus_width, score_height+bonus_height
            self.image = pygame.surface.Surface((width,height)).convert()
            self.image.fill(bg)
            draw_text(self.image, score_text, (height,0), fn_score,
                fg, bg, ('bottom','left'))
            draw_text(self.image, bonus_text, (height,width), fn_bonus,
                fg, bg, ('bottom','right'))
            self.rect = self.image.get_rect()
        else:
            self.image = get_font('score text').render(score_text, 1, fg, bg)
            self.rect = self.image.get_rect()
        self.image.set_colorkey(bg, RLEACCEL)
        self.rect.bottomleft = pos
        self.y = self.rect.bottom
        game.groups.add(self, layer='enemies', over=True)
        self.fader = iter(Fader(255, 1.5))
        self.speed = game.speed()
    def update(self, *args):
        try:
            self.image.set_alpha(self.fader.next())
        except StopIteration:
            self.kill()
        except ValueError:
            self.kill()
        self.rect.top = self.y = self.y - self.speed / 2.0

class Stage(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.value = 0
        self.prev_value = -1
        self.image = None
        self.update()
        self.rect = self.image.get_rect()
        self.rect.topleft = layout().stage
    def update(self, *args):
        if self.value != self.prev_value:
            self.image = get_font('gui').render(
                repr(self.value+1), True, color('stats'), color('transparent'))
            self.image.set_colorkey(color('transparent'), RLEACCEL)
    def add(self):
        self.value += 1
    def reset(self):
        self.value = 0
        self.prev_value = -1
        self.update()

class PlayerName(pygame.sprite.Sprite):
    def __init__(self, text):
        pygame.sprite.Sprite.__init__(self)
        self.text = text
        self.image = get_font('gui').render(
            text, True, color('stats'), color('transparent'))
        self.image.set_colorkey(color('transparent'), RLEACCEL)
        self.rect = self.image.get_rect()
        self.rect.topleft = layout().player_name

class Pointer(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image_show,self.rect = load_image(
            join_path('image','pointer7x7.png'), -1)
        self.image_hide = pygame.surface.Surface((1,1)).convert()
        self.image_hide.fill(color('transparent'))
        self.image_hide.set_colorkey(color('transparent'), RLEACCEL)
        self.image = self.image_show
        self.visible = settings.visible_mouse
    def update(self, *args):
        game = game_globals.game
        if self.visible == False:
            if game.state in (GET_MENU,FIRST):
                self.image = self.image_show
            else:
                self.image = self.image_hide
        else:
            self.image = self.image_show
        self_rect = self.rect
        self_rect.center = mouse_to_game(pygame.mouse.get_pos())
        if (game.window.is_fullscreen() or
            game._grab_mouse and game.state == PLAY) and \
        constrain(self_rect, game.window.rect):
#        if game._grab_mouse and game.state == PLAY and \
#        constrain(self_rect, game.window.rect):
            pygame.mouse.set_pos(game_to_mouse(self_rect.center))
    def go_home(self):
        game_rect = game_globals.game.window.rect
        x,y = game_rect.centerx,game_rect.bottom - 100
        self.set_pos((x,y))
        pygame.mouse.set_pos(game_to_mouse((x,y)))
    def get_pos(self):
        """position in game drawing subsurface"""
        return self.rect.center
    def get_real_pos(self):
        """position in window surface"""
        return game_to_mouse(self.rect.center)
    def set_pos(self, pos):
        """set to position in game drawing subsurface"""
        self.rect.center = pos
    def set_real_pos(self, pos):
        pygame.mouse.set_pos(pos)
        self.update()

def _init_module():
    pygame.init()
    # Make a large font for UI
    make_font('gui', GUI_FONT_NAME, GUI_FONT_SIZE)
    make_font('gui small', GUI_SMALL_FONT_NAME, GUI_SMALL_FONT_SIZE)
    make_font('score text', GUI_SCORE_TEXT_NAME, GUI_SCORE_TEXT_SIZE)
    make_font('score text 2', GUI_SCORE_TEXT_NAME, GUI_SCORE_TEXT_SIZE+2)
    make_font('score text 3', GUI_SCORE_TEXT_NAME, GUI_SCORE_TEXT_SIZE+6)
    make_font('score text 4', GUI_SCORE_TEXT_NAME, GUI_SCORE_TEXT_SIZE+10)
    make_font('score text 5', GUI_SCORE_TEXT_NAME, GUI_SCORE_TEXT_SIZE+15)

_init_module()
